import json
import logging
import os
from logging.handlers import TimedRotatingFileHandler
from sqlite3 import IntegrityError

import requests
from aligo import Aligo
from flask import Flask, render_template, request, url_for, redirect, abort, current_app

import db
from service import get_share_by_id, get_share, get_file, save_file, create_share, delete_share, get_file_path, \
    update_file, update_file_alias, delete_file

os.makedirs('log', exist_ok=True)
app = Flask(__name__)
app.config.from_mapping(
    SECRET_KEY='dev',
    DATABASE=os.path.join(app.instance_path, 'aliyun.sqlite'),
)
app.config.from_pyfile('config.py', silent=True)
try:
    os.makedirs(app.instance_path)
except OSError:
    pass

db.init_app(app)

ali = Aligo(level=logging.NOTSET, port=9003)

handler = TimedRotatingFileHandler(
    "log/flask.log", when="D", interval=1, backupCount=15,
    encoding="UTF-8", delay=False, utc=True)
handler.setFormatter(logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'))
app.logger.addHandler(handler)


@app.route('/')
@app.route('/index')
def index():
    return render_template('index.html', user=ali.get_user())


@app.route('/ng')
def ng():
    return current_app.send_static_file('AriaNg-1.3.6/index.html')


@app.route('/get_share_list')
def get_share_list():
    return get_share()


@app.route('/save_share', methods=['POST'])
def save_share():
    url = request.form.get('url')
    folder = request.form.get('folder')
    try:
        share = ali.share_link_extract_code(url)
        share_info = ali.get_share_info(share.share_id)
        create_share(share.share_id, share.share_pwd, share_info.share_name, folder)
        return dict({'error': ''})
    except KeyError:
        return dict({'error': '保存失败，请检查分享地址'})
    except IntegrityError:
        return dict({'error': '分享地址已存在'})
    except Exception as ex:
        app.logger.error(ex)
        return dict({'error': '未知错误'})


@app.route('/remove_share', methods=['POST'])
def remove_share():
    try:
        share_id = request.form.get('share_id')
        delete_share(share_id)
        return dict({'error': ''})
    except Exception as ex:
        app.logger.error(ex)
        return dict({'error': '删除分享失败'})


@app.route('/remove_file', methods=['POST'])
def remove_file():
    try:
        share_id = request.form.get('share_id')
        file_id = request.form.get('file_id')
        delete_file(share_id, file_id)
        return dict({'error': ''})
    except Exception as ex:
        app.logger.error(ex)
        return dict({'error': '删除文件失败'})


@app.route('/update_alias', methods=['POST'])
def update_alias():
    try:
        file_id = request.form.get('file_id')
        alias = request.form.get('alias')
        update_file_alias(file_id, alias)
        return dict({'error': ''})
    except Exception as ex:
        app.logger.error(ex)
        return dict({'error': '设置别名失败'})


@app.route('/files')
def files():
    try:
        share_id = request.args.get('share_id', '')
        if share_id == '':
            return redirect(url_for('index'))
        share_info = get_share_by_id(share_id)
        return render_template('files.html', user=ali.get_user(), share_info=share_info)
    except Exception as ex:
        app.logger.error(ex)


@app.route('/get_file_list')
def get_file_list():
    try:
        parent_file_id = request.args.get('parent_file_id', 'root')
        if parent_file_id == '':
            parent_file_id = 'root'
        share_id = request.args.get('share_id', '')
        share_token = ali.get_share_token(share_id)
        share_file_list = ali.get_share_file_list(share_token=share_token,
                                                  parent_file_id=parent_file_id)
        old_share_file_list = get_file(share_id, parent_file_id)
        res = []
        for new in share_file_list:
            temp = {'share_id': new.share_id, 'parent_file_id': parent_file_id, 'file_id': new.file_id,
                    'type': new.type, 'name': new.name, 'size': new.size, 'created_at': new.created_at,
                    'download_status': 0, 'alias': None}
            old_share_file = next((x for x in old_share_file_list if x['file_id'] == new.file_id), None)
            if old_share_file is None:
                save_file(temp)
            else:
                temp['download_status'] = old_share_file['download_status']
                temp['alias'] = old_share_file['alias']
            res.append(temp)
        return res
    except Exception as ex:
        app.logger.error(ex)
        return []


@app.route('/download', methods=['POST'])
def download():
    try:
        err = ''
        share_id = request.form.get('share_id')
        file_id = request.form.get('file_id')
        file_path_data = get_file_path(share_id, file_id)
        share_token = ali.get_share_token(share_id)
        res = ali.get_share_link_download_url(file_id=file_id, share_token=share_token)
        update_file(file_id, 1)
        file_path = '/'.join(['/downloads', file_path_data['folder'], file_path_data['alias']])
        print(file_path)
        if not res.download_url:
            err = f'文件 {file_path} 下载失败: 获取的url为空, 文件可能被屏蔽导致无法下载'
            app.logger.error(err)
            return dict({'error': err})
        # if os.path.exists(file_path):
        #     # update_file(file_id, 2)
        #     err = f'文件已存在,跳过下载 {file_path}'
        #     app.logger.error(err)
        #     return dict({'error': err})
        # if not os.path.exists(os.path.dirname(file_path)):
        #     os.makedirs(os.path.dirname(file_path), exist_ok=True)
        resp = requests.post("http://yxlix1.ddns.net:6800/jsonrpc", data=json.dumps({
            "jsonrpc": "2.0",
            "method": "aria2.addUri",
            "id": file_id,
            "params": [
                "token:87520xing",
                [res.download_url],
                {"dir": file_path, "referer": "https://www.aliyundrive.com/"},
            ]
        }))
        if resp.status_code != 200:
            err = f'下载失败： {resp.text}'
            app.logger.error(err)
            return dict({'error': err})
        # tmp_size = 0
        # with requests.get(url=res.download_url, headers={
        #     'Referer': 'https://www.aliyundrive.com/',
        # }, stream=True) as resp:
        #     if resp.status_code != 200:
        #         raise ValueError(f'无效下载链接或链接已过期 {resp.url}')
        #     llen = int(resp.headers.get('content-length', 0))
        #     progress_bar = tqdm(total=llen + tmp_size, unit='B', unit_scale=True, colour='#31a8ff')
        #     progress_bar.update(tmp_size)
        #     with open(file_path, 'wb') as f:
        #         for content in resp.iter_content(chunk_size=8388608):
        #             progress_bar.update(len(content))
        #             f.write(content)
        update_file(file_id, 2)
        return dict({'error': err})
    except Exception as ex:
        app.logger.error(ex)
        return dict({'error': '下载失败'})


@app.before_request
def limit_remote_addr():
    ips = ('127.0', '192.168', '222.221', '60.160', '106.61')
    for ip in ips:
        if '.'.join(request.remote_addr.split('.')[:2]) == ip:
            return
    abort(403)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9002, debug=False, use_reloader=False)
